home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Applications / SML⁄NJ 93+ / Documentation / examples / textbooks / working / ParsePrint.ML < prev    next >
Encoding:
Text File  |  1995-12-30  |  9.7 KB  |  345 lines  |  [TEXT/R*ch]

  1. (**** ML Programs from the book
  2.  
  3.   ML for the Working Programmer
  4.   by Lawrence C. Paulson, Computer Laboratory, University of Cambridge.
  5.   (Cambridge University Press, 1991)
  6.  
  7. Copyright (C) 1991 by Cambridge University Press.
  8. Permission to copy without fee is granted provided that this copyright
  9. notice and the DISCLAIMER OF WARRANTY are included in any copy.
  10.  
  11. DISCLAIMER OF WARRANTY.  These programs are provided `as is' without
  12. warranty of any kind.  We make no warranties, express or implied, that the
  13. programs are free of error, or are consistent with any particular standard
  14. of merchantability, or that they will meet your requirements for any
  15. particular application.  They should not be relied upon for solving a
  16. problem whose incorrect solution could result in injury to a person or loss
  17. of property.  If you do use the programs or functions in such a manner, it
  18. is at your own risk.  The author and publisher disclaim all liability for
  19. direct, incidental or consequential damages resulting from your use of
  20. these programs or functions.
  21. ****)
  22.  
  23.  
  24. (*** Basic library module.  From Chapter 9.  ***)
  25.  
  26. infix mem;
  27.  
  28. signature BASIC =
  29.   sig
  30.   exception Lookup
  31.   exception Nth
  32.   val minl : int list -> int
  33.   val maxl : int list -> int
  34.   val take : int * 'a list -> 'a list
  35.   val drop : int * 'a list -> 'a list
  36.   val nth : 'a list * int -> 'a
  37.   val mem : ''a * ''a list -> bool
  38.   val newmem : ''a * ''a list -> ''a list
  39.   val lookup : (''a * 'b) list * ''a -> 'b
  40.   val filter : ('a -> bool) -> 'a list -> 'a list
  41.   val exists : ('a -> bool) -> 'a list -> bool
  42.   val forall : ('a -> bool) -> 'a list -> bool
  43.   val foldleft : ('a * 'b -> 'a) -> 'a * 'b list -> 'a
  44.   val foldright : ('a * 'b -> 'b) -> 'a list * 'b -> 'b
  45.   end;
  46.   
  47.  
  48. functor BasicFUN() : BASIC =
  49.   struct
  50.   fun minl[m] : int = m
  51.     | minl(m::n::ns) = if m<n  then  minl(m::ns)  else  minl(n::ns);
  52.  
  53.   fun maxl[m] : int = m
  54.     | maxl(m::n::ns) = if m>n  then  maxl(m::ns)  else  maxl(n::ns);
  55.  
  56.   fun take (n, []) = []
  57.     | take (n, x::xs) =  if n>0 then x::take(n-1,xs)  
  58.              else  [];
  59.  
  60.   fun drop (_, [])    = []
  61.     | drop (n, x::xs) = if n>0 then drop (n-1, xs) 
  62.                    else x::xs;
  63.  
  64.   exception Nth;
  65.   fun nth (l,n) =    (*numbers the list elements [x0,x1,x2,...] *)
  66.     case drop(n,l) of [] => raise Nth
  67.             | x::_ => x;
  68.  
  69.   fun x mem []  =  false
  70.     | x mem (y::l)  =  (x=y) orelse (x mem l);
  71.  
  72.   (*insertion into list if not already there*)
  73.   fun newmem(x,xs) = if x mem xs then  xs   else  x::xs;
  74.  
  75.   exception Lookup;
  76.   fun lookup ([], a) = raise Lookup
  77.     | lookup ((x,y)::pairs, a) = if a=x then y else lookup(pairs, a);
  78.  
  79.   fun filter pred [] = []
  80.     | filter pred (x::xs) =
  81.     if pred(x) then x :: filter pred xs  
  82.     else  filter pred xs;
  83.  
  84.   fun exists pred []      = false
  85.     | exists pred (x::xs) = (pred x)  orelse  exists pred xs;
  86.  
  87.   fun forall pred []      = true
  88.     | forall pred (x::xs) = (pred x)  andalso  forall pred xs;
  89.  
  90.   fun foldleft f (e, [])    = e
  91.     | foldleft f (e, x::xs) = foldleft f (f(e,x), xs);
  92.  
  93.   fun foldright f ([],    e) = e
  94.     | foldright f (x::xs, e) = f(x, foldright f (xs,e));
  95. end;
  96.  
  97.  
  98. (*** Lexical Analysis -- Scanning.  From Chapter 9.  ***)
  99.  
  100. (*Formal parameter of LexicalFUN*)
  101. signature KEYWORD =
  102.   sig
  103.   val alphas: string list
  104.   and symbols: string list
  105.   end;
  106.  
  107. (*Result signature of LexicalFUN*)
  108. signature LEXICAL =
  109.   sig
  110.   datatype token = Id of string | Key of string
  111.   val scan : string -> token list
  112.   end;
  113.  
  114.  
  115. (*All characters are covered except octal 0-41 (nul-space) and 177 (del),
  116.   which are ignored. *)
  117. functor LexicalFUN (structure Basic: BASIC 
  118.             and       Keyword: KEYWORD) : LEXICAL =
  119.   struct
  120.   local open Basic in
  121.   datatype token = Key of string  |  Id of string;
  122.  
  123.   fun is_letter_or_digit c =
  124.       "A"<=c andalso c<="Z" orelse
  125.       "a"<=c andalso c<="z" orelse
  126.       "0"<=c andalso c<="9";
  127.  
  128.   val specials = explode"!@#$%^&*()+-={}[]:\"|;'\\,./?`_~<>";
  129.  
  130.   (*scanning of an alphanumeric identifier or keyword*)
  131.   fun alphanum (id, c::cs) =
  132.     if is_letter_or_digit c then  alphanum (id^c, cs)
  133.                 else  (id, c::cs)
  134.     | alphanum (id, []) = (id, []);
  135.  
  136.   fun tokenof a = if a mem Keyword.alphas  then  Key(a)  else  Id(a);
  137.  
  138.   (*scanning of a symbolic keyword*)
  139.   fun symbolic (sy, c::cs) =
  140.     if sy mem Keyword.symbols orelse not (c mem specials)
  141.         then  (sy, c::cs)
  142.     else  symbolic (sy^c, cs)
  143.     | symbolic (sy, []) = (sy, []);
  144.  
  145.   fun scanning (toks, []) = rev toks    (*end of chars*)
  146.     | scanning (toks, c::cs) =
  147.     if is_letter_or_digit c 
  148.     then (*identifier or keyword*)
  149.          let val (id, cs2) = alphanum(c, cs)
  150.          in  scanning (tokenof id :: toks, cs2)
  151.          end
  152.     else if c mem specials
  153.     then (*special symbol*)
  154.          let val (sy, cs2) = symbolic(c, cs)
  155.          in  scanning (Key sy :: toks, cs2)
  156.          end
  157.     else (*spaces, line breaks, strange characters are ignored*)
  158.          scanning (toks, cs);
  159.  
  160.   (*Scanning a list of characters into a list of tokens*)
  161.   fun scan a = scanning([], explode a);
  162.   end
  163.   end;
  164.  
  165.  
  166. (*** Parsing functionals.  From Chapter 9.  ***)
  167.  
  168. infix 5 --;
  169. infix 3 >>;
  170. infix 0 ||;
  171.  
  172. signature PARSE =
  173.   sig
  174.   exception SynError of string
  175.   type token
  176.   val reader: (token list -> 'a * 'b list) -> string -> 'a
  177.   val -- : ('a -> 'b * 'c) * ('c -> 'd * 'e) -> 'a -> ('b * 'd) * 'e
  178.   val >> : ('a -> 'b * 'c) * ('b -> 'd) -> 'a -> 'd * 'c
  179.   val || : ('a -> 'b) * ('a -> 'b) -> 'a -> 'b
  180.   val $  : string -> token list -> string * token list
  181.   val empty : 'a -> 'b list * 'a
  182.   val id : token list -> string * token list
  183.   val infixes :
  184.       (token list -> 'a * token list) * (string -> int) *
  185.       (string -> 'a -> 'a -> 'a) -> token list -> 'a * token list
  186.   val repeat : ('a -> 'b * 'a) -> 'a -> 'b list * 'a
  187.   end;
  188.  
  189.  
  190. functor ParseFUN (Lex: LEXICAL) : PARSE =
  191.   struct
  192.   type token = Lex.token;
  193.   exception SynError of string;
  194.  
  195.   (*Phrase consisting of the keyword 'a' *)
  196.   fun $a (Lex.Key b :: toks) =
  197.         if a=b then (a,toks) else raise SynError a
  198.     | $a _ = raise SynError "Symbol expected";
  199.  
  200.   (*Phrase consisting of an identifier*)
  201.   fun id (Lex.Id a :: toks) = (a,toks)
  202.     | id toks = raise SynError "Identifier expected";
  203.  
  204.   (*Application of f to the result of a phrase*)
  205.   fun (ph>>f) toks = 
  206.       let val (x,toks2) = ph toks
  207.       in  (f x, toks2)  end;
  208.  
  209.   (*Alternative phrases*)
  210.   fun (ph1 || ph2) toks = ph1 toks   handle SynError _ => ph2 toks;
  211.  
  212.   (*Consecutive phrases*)
  213.   fun (ph1 -- ph2) toks = 
  214.       let val (x,toks2) = ph1 toks
  215.       val (y,toks3) = ph2 toks2
  216.       in  ((x,y), toks3)  end;
  217.  
  218.   fun empty toks = ([],toks);
  219.  
  220.   (*Zero or more phrases*)
  221.   fun repeat ph toks = (   ph -- repeat ph >> (op::)
  222.                         || empty   ) toks;
  223.  
  224.   fun infixes (ph,prec_of,apply) = 
  225.     let fun over k toks = next k (ph toks)
  226.         and next k (x, Lex.Key(a)::toks) = 
  227.               if prec_of a < k then (x, Lex.Key a :: toks)
  228.               else next k ((over (prec_of a) >> apply a x) toks)
  229.           | next k (x, toks) = (x, toks)
  230.     in  over 0  end;
  231.  
  232.   fun reader ph a =   (*Scan and parse, checking that no tokens remain*)
  233.      (case ph (Lex.scan a) of 
  234.           (x, []) => x
  235.         | (_, _::_) => raise SynError "Extra characters in phrase");
  236.  
  237.   end;
  238.  
  239.  
  240. (*** Pretty printing.  See Oppen (1980).  From Chapter 8.  ***)
  241.  
  242. signature PRETTY = 
  243.   sig
  244.    type T
  245.    val blo : int * T list -> T
  246.    val str : string -> T
  247.    val brk : int -> T
  248.    val pr  : outstream * T * int -> unit
  249.    end;
  250.  
  251.  
  252. functor PrettyFUN () : PRETTY =
  253.   struct
  254.   datatype T = 
  255.       Block of T list * int * int     (*indentation, length*)
  256.     | String of string
  257.     | Break of int;            (*length*)
  258.  
  259.   (*Add the lengths of the expressions until the next Break; if no Break then
  260.     include "after", to account for text following this block. *)
  261.   fun breakdist (Block(_,_,len)::sexps, after) = len + breakdist(sexps, after)
  262.     | breakdist (String s :: sexps, after) = size s + breakdist (sexps, after)
  263.     | breakdist (Break _ :: sexps, after) = 0
  264.     | breakdist ([], after) = after;
  265.  
  266.   fun pr (os, sexp, margin) =
  267.    let val space = ref margin
  268.  
  269.        fun blanks 0 = ()
  270.          | blanks n = (output(os," ");  space := !space - 1; 
  271.                        blanks(n-1))
  272.  
  273.        fun newline () = (output(os,"\n");  space := margin)
  274.  
  275.        fun printing ([], _, _) = ()
  276.      | printing (sexp::sexps, blockspace, after) =
  277.       (case sexp of
  278.            Block(bsexps,indent,len) =>
  279.           printing(bsexps, !space-indent, breakdist(sexps,after))
  280.          | String s => (output(os,s);   space := !space - size s)
  281.          | Break len => 
  282.          if len + breakdist(sexps,after) <= !space 
  283.          then blanks len
  284.          else (newline();  blanks(margin-blockspace));
  285.         printing (sexps, blockspace, after))
  286.    in  printing([sexp], margin, 0);  newline()  end;
  287.  
  288.   fun length (Block(_,_,len)) = len
  289.     | length (String s) = size s
  290.     | length (Break len) = len;
  291.  
  292.   val str = String  and  brk = Break;
  293.  
  294.   fun blo (indent,sexps) =
  295.     let fun sum([], k) = k
  296.       | sum(sexp::sexps, k) = sum(sexps, length sexp + k)
  297.     in  Block(sexps,indent, sum(sexps,0))  end;
  298.   end;
  299.  
  300.  
  301. (*** Types as an example of parsing ***)
  302.  
  303. signature TYPE = 
  304.   sig
  305.   datatype typ = Con of string * typ list | Var of string
  306.   val pr : typ -> unit
  307.   val read : string -> typ
  308.   end;
  309.  
  310. functor TypeFUN (structure Parse: PARSE 
  311.          and       Pretty: PRETTY) : TYPE =
  312.   struct
  313.   datatype typ = Con of string * typ list
  314.            | Var of string;
  315.  
  316.   local (** Parsing **)
  317.     fun makefun ((S,_),T) = Con("->",[S,T]);
  318.     open Parse 
  319.  
  320.     fun typ toks =
  321.      (   atom -- $"->" -- typ            >> makefun
  322.       || atom    
  323.        ) toks
  324.     and atom toks =
  325.       (   $"'" -- id                >> (Var o op^)
  326.        || $"(" -- typ -- $")"            >> (#2 o #1)
  327.        ) toks;
  328.   in
  329.     val read = reader typ;
  330.   end;
  331.  
  332.   local (** Displaying **)
  333.     open Pretty
  334.  
  335.     fun typ (Var a) = str a
  336.       | typ (Con("->",[S,T])) = blo(0, [atom S, str " ->", brk 1, typ T])
  337.      and atom (Var a) = str a
  338.        | atom T = blo(1, [str"(", typ T, str")"]);
  339.   in
  340.     fun pr T = Pretty.pr (std_out, typ T, 50)
  341.   end
  342. end;
  343.  
  344.  
  345.